docs: improve how the repository presents itself - #113
Merged
Conversation
Three gaps that all cost the project the same thing — someone finds Onebox and leaves without understanding what it is or how to engage with it. Issue and pull request templates. There were none, so a bug report arrived without a version, a target host, or the plan output that shows the discrepancy, and a proposal arrived without saying whether it widens the one-application, one-host scope. The templates ask for exactly what a maintainer needs on the first round trip, and the config points security reports at SECURITY.md rather than a public issue. A social preview card. GitHub and every chat client showed a generic grey box for links to this repository. Worse, Starlight emits `twitter:card: summary_large_image` and never an image to pair with it, so links to onebox.run unfurled as an empty large card. The card is rendered from `docs/media/social-card.typ`, and the site serves it as its og:image. A comparison table. The README never named Docker Compose, Kamal, Dokku, Coolify, Ansible, or Kubernetes, which are the words someone uses when they are looking for a tool in this space. Each row states the boundary difference rather than a feature score, and the Kubernetes row says plainly what Onebox gives up. Ran `just check`: passes. Did not run `just e2e`; nothing here touches the binary or the deployment path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review of the first commit found the card carrying two failure modes that nothing would report. The mark was copied into `docs/media/social-card-mark.svg`, byte-identical to the one in `site/public/favicon.svg` and connected to it by nothing. The favicon comment records that four earlier drafts of that mark died before this one; the next revision would have reached the site and left the card — the most-seen surface — drawing a retired logo. Typst reads the favicon directly, so the copy is gone and the render is unchanged, pixel for pixel. The PNG had no generator and no check. `just social-card` renders it, and does the part a hand-typed command cannot: typst warns about an unknown font family and still exits 0, so it verifies the font was actually found and fails when it was not. The typst version is pinned because another release re-lays out every glyph. CI has no font path and so cannot re-render, but `site-build` now asserts the committed PNG exists and matches the dimensions the head advertises — the previous commit emitted `og:image` unconditionally, so renaming the asset would have left every page pointing at a 404. Also corrects a comment from the previous commit: `astro.config.mjs` sets `site` unconditionally, so the fallback is not a configuration this repository ships. Ran `just check`: passes. Exercised `just social-card` against an empty font directory (fails, as intended) and a real one (renders a card identical to the committed PNG), and `check-social-card.mjs` against a missing asset and a wrong-sized one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two parity fixes with the same change in the Fanout repository, where the review that prompted them ran. `just social-card` wrote straight to `site/public/social-card.png` and only then checked whether typst had fallen back to a substitute face. It failed correctly, but the wrong card was already on disk, and the next person to look would find a card that no recipe claims to have produced. It renders to a temporary file and moves it into place once the render is known good. The footer was placed at a fixed offset out of flow, so a longer headline would have drawn the divider through the body copy with typst reporting nothing. Flexible space pushes it down instead: the overflow spills onto a second page, and a two-page render fails the PNG export outright. Ran `just check`: passes. The card re-renders byte-identically after the footer change, the recipe leaves the committed PNG untouched when the font is missing, and a deliberately overlong headline fails the export. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The comment justified the og:image check by saying an unfurl is the surface nobody on the team looks at. That is a claim about colleagues in a public repository, and it is not what makes the check worth having. Says what the failure actually looks like instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The hero comment credited two other companies' landing pages for the decision to name the category in the first clause. The reasoning holds without them, and a public repository is a poor place to record which competitors were studied. Keeps the principle, drops the names. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`mktemp -t social-card` reserves a name, and the recipe then appended `.png` to it — so typst wrote to a path nothing had reserved, the reserved file was left behind empty on every run, and the trap cleaned up only the render. A temporary directory reserves the whole name. Also handles a relative `og:image` in the site check. The tag is hand-written and someone could reasonably make it relative; Open Graph consumers do not resolve those, and the check now says so rather than failing on a URL parse error. Ran `just check`: passes. `just social-card` re-renders the committed PNG byte-identically. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
vishr
added a commit
that referenced
this pull request
Aug 24, 2026
* docs: improve how the repository presents itself Three gaps that all cost the project the same thing — someone finds Onebox and leaves without understanding what it is or how to engage with it. Issue and pull request templates. There were none, so a bug report arrived without a version, a target host, or the plan output that shows the discrepancy, and a proposal arrived without saying whether it widens the one-application, one-host scope. The templates ask for exactly what a maintainer needs on the first round trip, and the config points security reports at SECURITY.md rather than a public issue. A social preview card. GitHub and every chat client showed a generic grey box for links to this repository. Worse, Starlight emits `twitter:card: summary_large_image` and never an image to pair with it, so links to onebox.run unfurled as an empty large card. The card is rendered from `docs/media/social-card.typ`, and the site serves it as its og:image. A comparison table. The README never named Docker Compose, Kamal, Dokku, Coolify, Ansible, or Kubernetes, which are the words someone uses when they are looking for a tool in this space. Each row states the boundary difference rather than a feature score, and the Kubernetes row says plainly what Onebox gives up. Ran `just check`: passes. Did not run `just e2e`; nothing here touches the binary or the deployment path. * docs: gate the social card instead of trusting it Review of the first commit found the card carrying two failure modes that nothing would report. The mark was copied into `docs/media/social-card-mark.svg`, byte-identical to the one in `site/public/favicon.svg` and connected to it by nothing. The favicon comment records that four earlier drafts of that mark died before this one; the next revision would have reached the site and left the card — the most-seen surface — drawing a retired logo. Typst reads the favicon directly, so the copy is gone and the render is unchanged, pixel for pixel. The PNG had no generator and no check. `just social-card` renders it, and does the part a hand-typed command cannot: typst warns about an unknown font family and still exits 0, so it verifies the font was actually found and fails when it was not. The typst version is pinned because another release re-lays out every glyph. CI has no font path and so cannot re-render, but `site-build` now asserts the committed PNG exists and matches the dimensions the head advertises — the previous commit emitted `og:image` unconditionally, so renaming the asset would have left every page pointing at a 404. Also corrects a comment from the previous commit: `astro.config.mjs` sets `site` unconditionally, so the fallback is not a configuration this repository ships. Ran `just check`: passes. Exercised `just social-card` against an empty font directory (fails, as intended) and a real one (renders a card identical to the committed PNG), and `check-social-card.mjs` against a missing asset and a wrong-sized one. * docs: keep a bad card render out of the tree Two parity fixes with the same change in the Fanout repository, where the review that prompted them ran. `just social-card` wrote straight to `site/public/social-card.png` and only then checked whether typst had fallen back to a substitute face. It failed correctly, but the wrong card was already on disk, and the next person to look would find a card that no recipe claims to have produced. It renders to a temporary file and moves it into place once the render is known good. The footer was placed at a fixed offset out of flow, so a longer headline would have drawn the divider through the body copy with typst reporting nothing. Flexible space pushes it down instead: the overflow spills onto a second page, and a two-page render fails the PNG export outright. Ran `just check`: passes. The card re-renders byte-identically after the footer change, the recipe leaves the committed PNG untouched when the font is missing, and a deliberately overlong headline fails the export. * docs: neutralise a comment about the team The comment justified the og:image check by saying an unfurl is the surface nobody on the team looks at. That is a claim about colleagues in a public repository, and it is not what makes the check worth having. Says what the failure actually looks like instead. * docs: explain the tagline without naming other vendors The hero comment credited two other companies' landing pages for the decision to name the category in the first clause. The reasoning holds without them, and a public repository is a poor place to record which competitors were studied. Keeps the principle, drops the names. * docs: stop the card recipe leaking a temp file `mktemp -t social-card` reserves a name, and the recipe then appended `.png` to it — so typst wrote to a path nothing had reserved, the reserved file was left behind empty on every run, and the trap cleaned up only the render. A temporary directory reserves the whole name. Also handles a relative `og:image` in the site check. The tag is hand-written and someone could reasonably make it relative; Open Graph consumers do not resolve those, and the check now says so rather than failing on a URL parse error. Ran `just check`: passes. `just social-card` re-renders the committed PNG byte-identically. ---------
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Three gaps in how the repository meets someone who has just found it.
Issue and pull request templates.
.github/held only workflows, so a bug report could arrive without a version, a target host, or the plan output that shows the discrepancy, and a proposal could arrive without saying whether it widens the one-application, one-host scope.config.ymlturns off blank issues and points security reports at SECURITY.md.A social preview card, and an og:image. Links to this repository unfurled as a generic grey box. Separately, Starlight emits
twitter:card: summary_large_imagebut never anog:imageto pair with it, so links to onebox.run unfurled as an empty large card — the worst of both.site/src/components/Head.astronow emitsog:image, its dimensions, an alt line, andtwitter:image.The card is generated:
just social-cardrendersdocs/media/social-card.typat 960pt × 480pt, exactly 1280 × 640 px at 96 ppi. The recipe pins typst 0.15.1, requires IBM Plex Mono onONEBOX_FONT_PATHand fails when the face is missing — typst only warns and exits 0, so the alternative is silently shipping a card set in a fallback face — and installs the PNG from a temporary directory only once the render is known good. The mark is read fromsite/public/favicon.svgrather than copied, so a revised favicon reaches the card.CI has no font path and cannot re-render the card, so the gate does the part it honestly can:
site-buildnow runssite/scripts/check-social-card.mjs, which asserts every built page carries anog:image, that the target is actually indist/, and that its real PNG dimensions match the hand-typedog:image:width/height.A comparison table. The README never contained the words Docker Compose, Kamal, Dokku, CapRover, Coolify, Ansible, Kubernetes, or Terraform, which is what someone types when they are shopping in this space. Each row states the boundary difference rather than a feature score, and the Kubernetes row says outright what Onebox gives up.
Still manual after this
The GitHub social preview image is uploaded through Settings → General → Social preview; there is no API for it. Use
site/public/social-card.png.What I ran
just check— passes, includingsite-build. Verified insite/dist/index.htmlthat the built head carriesog:imagepointing athttps://onebox.run/social-card.pngand that the asset is emitted. Exercisedjust social-cardagainst an empty font directory (fails, committed PNG untouched) and a real one (re-renders byte-identically), andcheck-social-card.mjsagainst a missing asset and a wrong-sized one.Did not run
just e2e: nothing here touches the binary or the deployment path.